﻿/**
 * @file opus_decoder_test.cpp
 * Copyright (c) Gaaagaa. All rights reserved.
 * 
 * @author  : Gaaagaa
 * @date    : 2020-03-09
 * @version : 1.0.0.0
 * @brief   : PCM 音频数据解码（测试 opus_decoder_t）。
 */

#include "audio_opus.h"
#include "fwave_pcm.h"

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif // _MSC_VER

#include <vector>
#include <stdio.h>
#include <errno.h>

////////////////////////////////////////////////////////////////////////////////

#include "opus_fhelper.inl"

/////////////////////////////////////////////////////////////////////////////////

int main(int argc, char * argv[])
{
    x_errno_t xerr_no = X_ERR_UNKNOW;
    x_int32_t xit_err = X_ERR_UNKNOW;

    //======================================

    FILE * fopus_reader = X_NULL;
    fwave_wpcm_t fwave_wpcm;
    opus_decoder_t opus_decoder;

    x_uint32_t xut_ibytes = 256 * 1024;
    x_uint32_t xut_obytes = 256 * 1024;

    std::vector< x_byte_t > xvec_input (xut_ibytes, 0);
    std::vector< x_byte_t > xvec_output(xut_obytes, 0);

    //======================================

    if (argc < 3)
    {
        printf("Usage: \n\t %s < opus input file > < wave-pcm-s16 output file >\n", argv[0]);
        return -1;
    }

    //======================================

    fopus_reader = fopen(argv[1], "rb");
    if (X_NULL == fopus_reader)
    {
        printf("fopen([%s], \"rb\") return X_NULL, errno: %d\n", argv[1], errno);
        return -1;
    }

    x_uint32_t xut_ctxt = 0;
    if (0 == opus_rhead(fopus_reader, &xut_ctxt))
    {
        printf("opus_rhead() return 0, errno: %d\n", errno);
        fclose(fopus_reader);
        return -1;
    }

    //======================================

    xerr_no = fwave_wpcm.open(
                    argv[2],
                    XOPUS_CR(xut_ctxt),
                    XOPUS_CT(xut_ctxt),
                    XOPUS_CC(xut_ctxt));
    if (XERR_FAILED(xerr_no))
    {
        printf("fwave_wpcm.open([%s], [%d], [%d], [%d]) return error: %s\n",
                argv[2], XOPUS_CR(xut_ctxt), XOPUS_CT(xut_ctxt), XOPUS_CC(xut_ctxt),
               fwave_wpcm_t::xerrno_name(xerr_no));
        if (X_NULL != fopus_reader)
        {
            fclose(fopus_reader);
            fopus_reader = X_NULL;
        }
        return -1;
    }

    //======================================

    xerr_no = opus_decoder.open(
                    (x_uint16_t)XOPUS_CT(xut_ctxt),
                    (x_uint16_t)XOPUS_CC(xut_ctxt),
                    (x_uint32_t)XOPUS_CR(xut_ctxt));
    if (XERR_FAILED(xerr_no))
    {
        printf("opus_decoder.open() return error : %s\n",
               opus_decoder_t::xerrno_name(xerr_no));
        if (X_NULL != fopus_reader)
        {
            fclose(fopus_reader);
            fopus_reader = X_NULL;
        }
        return -1;
    }

    //======================================

    for (x_bool_t xbt_eof = X_FALSE; !xbt_eof; )
    {
        //======================================
        // read opus frame

        xut_ibytes = (x_uint32_t)xvec_input.size();
        x_int32_t xit_read = opus_rframe(fopus_reader, xvec_input.data(), xut_ibytes);
        if (xit_read <= 0)
        {
            xbt_eof = X_TRUE;
            break;
        }

        if (xit_read != (x_int32_t)xut_ibytes)
        {
            printf("read size error: (xit_read[%d] != xut_ibytes[%d])\n",
                   xit_read, xut_ibytes);
            break;
        }

        //======================================
        // decode opus frame

        xut_obytes = (x_uint32_t)xvec_output.size();
        xerr_no = opus_decoder.decode(
                        xvec_output.data(),
                        xut_obytes,
                        xvec_input.data(),
                        xut_ibytes);
        if (XERR_FAILED(xerr_no))
        {
            printf("opus_decoder.decode(, [%d], , [%d]) return error: %d\n",
                    xut_obytes, xut_ibytes, XERR_HINO(xerr_no));
            break;
        }

        printf("decode: input[%d], output[%d]\n", xut_ibytes, xut_obytes);

        //======================================
        // output pcm bitstream

        fwave_wpcm.write(xvec_output.data(), xut_obytes);

        //======================================
    }

    //======================================

    if (X_NULL != fopus_reader)
    {
        fclose(fopus_reader);
        fopus_reader = X_NULL;
    }

    opus_decoder.close();
    fwave_wpcm.close();

    //======================================

    return 0;
}


